﻿// Copyright (c) Inossem. All rights reserved.
// Licensed under the LGPL-3.0 license. See LICENSE file in the project root for full license information.
using DWF.Studio.Custom;
using DWF.Studio.ISerivces;
using DWF.Studio.Models;
using DWF.Studio.Models.Enum;
using DWF.Studio.Project;
using DWF.Studio.Script;
using DWF.Studio.Script.Implementation;
using DWF.Studio.ScriptEngine.IPC;
using DWF.Studio.ScriptEngine.IPC.Msg;
using DWF.Studio.ScriptEngine.IPC.WorkFlow;
using DWF.Studio.Share.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DWF.Studio.Services
{
    internal class ExecutionService : IExecutionService
    {
        private static readonly ExecutionService _executionService = new ExecutionService();

        /// <summary>
        /// 工程管理类引用
        /// </summary>
        public static ExecutionService Instance
        {
            get
            {
                return _executionService;
            }
        }

        private IScriptExecutor _scriptExcutor = null;

        private ExecuteStatus _currentStatus = ExecuteStatus.Idle;

        private IProjectParamDetailSerivce _projectParamDetailSerivce = null;

        private ExecutionService()
        {
            _projectParamDetailSerivce = new ProjectParamDetailSerivce();
        }

        public ExecuteStatus GetCurrentStatus()
        {
            return _currentStatus;
        }

        public void Execute(ScriptBase script)
        {
            if (script != null)
            {
                _currentStatus = ExecuteStatus.Executing;
                setScriptExcutor(script);
                try
                {
                    if (script.IsStart)
                    {
                        var param = getProjectParams();
                        var executionId = _scriptExcutor.Execute(script.ProjectDirectory, script.FilePath, param);
                    }
                    else
                    {
                        var executionId = _scriptExcutor.Execute(script.ProjectDirectory, script.FilePath);
                    }
                }
                catch
                {
                    _scriptExcutor = null;
                    _currentStatus = ExecuteStatus.Idle;

                    throw;
                }
            }
        }

        public void Debug(ScriptBase script)
        {
            if (script != null)
            {
                _currentStatus = ExecuteStatus.Debuging;
                setScriptExcutor(script);
                try
                {
                    if (script.IsStart)
                    {
                        var param = getProjectParams();
                        var executionId = _scriptExcutor.Debug(script.ProjectDirectory, script.FilePath, param, false);
                    }
                    else
                    {
                        var executionId = _scriptExcutor.Debug(script.ProjectDirectory, script.FilePath, false);
                    }
                }
                catch
                {
                    _scriptExcutor = null;
                    _currentStatus = ExecuteStatus.Idle;

                    throw;
                }
            }
        }

        public void Debug()
        {
            _currentStatus = ExecuteStatus.Debuging;
            _scriptExcutor.DebugResume();
        }

        public void DebugByStep(ScriptBase script)
        {
            if (script != null)
            {
                _currentStatus = ExecuteStatus.DebugByStep;
                setScriptExcutor(script);
                try
                {
                    if (script.IsStart)
                    {
                        var param = getProjectParams();
                        var executionId = _scriptExcutor.Debug(script.ProjectDirectory, script.FilePath, param, true);
                    }
                    else
                    {
                        var executionId = _scriptExcutor.Debug(script.ProjectDirectory, script.FilePath, true);
                    }
                }
                catch
                {
                    _scriptExcutor = null;
                    _currentStatus = ExecuteStatus.Idle;

                    throw;
                }
            }
        }

        public void DebugByStep()
        {
            _currentStatus = ExecuteStatus.DebugByStep;
            _scriptExcutor.DebugStepOver();
        }

        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            if (_scriptExcutor != null)
            {
                _scriptExcutor.Cancel();
            }
        }

        public IEnumerable<TrackingInfo> DebugTrackInfo(FrameInfoBase stepInfo)
        {
            IEnumerable<TrackingInfo> trackinginfo = null;

            if (stepInfo is WorkflowFrameInfo)
            {
                trackinginfo = convertWFToTrackingInfo(stepInfo as WorkflowFrameInfo);
            }

            return trackinginfo;
        }

        public bool DebugTrackLocation(ScriptBase script, string location)
        {
            bool isHitBreakpoint = false;
            if (script != null)
            {
                if (script is WorkflowScript)
                {
                    if (_currentStatus == ExecuteStatus.Debuging)
                    {
                        isHitBreakpoint = script.Debug(location);

                        if (isHitBreakpoint)
                        {
                            _scriptExcutor.CallDebugInfos();
                        }
                        else
                        {
                            _scriptExcutor.DebugResume();
                        }
                    }
                    else if (_currentStatus == ExecuteStatus.DebugByStep)
                    {
                        script.DebugByStep(location);
                        isHitBreakpoint = true;
                        _scriptExcutor.CallDebugInfos();
                    }
                    else if (_currentStatus == ExecuteStatus.Terminal)
                    {
                        _scriptExcutor.DebugResume();
                    }
                }
            }
            else
            {
                _scriptExcutor.DebugResume();
            }

            return isHitBreakpoint;
        }

        public void Finish(IEnumerable<ScriptBase> scripts)
        {
            foreach (var script in scripts)//查找 是否脚本已经被显示
            {
                script.DebugEnd();//清理ui追踪标记。
            }

            _scriptExcutor = null;
            _currentStatus = ExecuteStatus.Idle;
        }

        private IEnumerable<TrackingInfo> convertWFToTrackingInfo(WorkflowFrameInfo stepInfo)
        {
            List<TrackingInfo> result = new List<TrackingInfo>();

            if (stepInfo.Arguments != null)
            {
                foreach (var argument in stepInfo.Arguments)
                {
                    var trackingInfo = new TrackingInfo()
                    {
                        Category = "Arguments",
                        Name = argument.Name,
                        ActivityName = argument.ActivityName,
                        Type = argument.TypeName,
                        Value = argument.Value
                    };

                    result.Add(trackingInfo);
                }
            }

            if (stepInfo.Variables != null)
            {
                foreach (var variable in stepInfo.Variables)
                {
                    var trackingInfo = new TrackingInfo()
                    {
                        Category = "Variables",
                        Name = variable.Name,
                        ActivityName = variable.ActivityName,
                        Type = variable.TypeName,
                        Value = variable.Value
                    };

                    result.Add(trackingInfo);
                }
            }

            return result;
        }

        /// <summary>
        /// Carl 20210629 单步调试切换调试修改debug状态
        /// </summary>
        public void Continue()
        {
            if (_scriptExcutor != null)
            {
                _currentStatus = ExecuteStatus.Debuging;
                _scriptExcutor.DebugResume();
            }
        }

        private void setScriptExcutor(ScriptBase script)
        {
            if (script is WorkflowScript)
            {
                _scriptExcutor = ScriptExecutorSet.WorkflowExcutor;
            }
        }

        private Dictionary<string, object> getProjectParams()
        {
            var projectParams = new Dictionary<string, object>();
            var detail = _projectParamDetailSerivce.GetProjectParamDetail();
            if (detail.Input != null && detail.Input.Count > 0)
            {
                var input = detail.Input;
                foreach (var param in input)
                {
                    if (param.ParamType == EProjectParamType.Number)
                    {
                        decimal value;
                        if (Decimal.TryParse(param.Value, out value))
                        {
                            projectParams.Add(param.Name, value);
                        }
                    }
                    else if (param.ParamType == EProjectParamType.Boolean)
                    {
                        bool value;
                        if (Boolean.TryParse(param.Value, out value))
                        {
                            projectParams.Add(param.Name, value);
                        }
                    }
                    else if (param.ParamType == EProjectParamType.String)
                    {
                        projectParams.Add(param.Name, param.Value);
                    }
                    else if (param.ParamType == EProjectParamType.File)
                    {
                        projectParams.Add(param.Name, param.Value);
                    }
                }
            }

            return projectParams;
        }

        public void Terminate(ScriptBase terminalScript, string location)
        {
            if (terminalScript is WorkflowScript)
            {
                ((WorkflowScript)terminalScript).SelectActivityById(location);
            }
            _currentStatus = ExecuteStatus.Terminal;
        }
        public void ActivitySelectionById(ScriptBase script, string location)
        {
            if (script is WorkflowScript)
            {
                ((WorkflowScript)script).ActivitySelectionById(location);
            }
        }
        public void RefreshBreakpoints(ScriptBase script)
        {
            _scriptExcutor?.RefreshBreakpoint(script.FilePath);
        }
        public void ChangeAllBreakpoints(ScriptBase script)
        {
            _scriptExcutor?.RefreshBreakpoint(script.FilePath);
        }
    }
}
